// [[ OnflowGenerator File UUID: bffc9713468340adaa3eefe23295b48c  ]]
package com.itdct.onflow.system.monitor.manager

import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.itdct.onflow.core.config.onflow.MonitorConfig
import com.itdct.onflow.core.extend.insertEx
import com.itdct.onflow.core.extend.logDebug
import com.itdct.onflow.core.extend.updateEx
import com.itdct.onflow.core.util.RedisReentrantLock
import com.itdct.onflow.core.util.RedisUtil
import com.itdct.onflow.system.common.base.BaseManager
import com.itdct.onflow.system.monitor.constant.SysMachineInfoConst
import com.itdct.onflow.system.monitor.entity.SysMachineInfoEntity
import com.itdct.onflow.system.monitor.entity.SysMachineReportEntity
import com.itdct.onflow.system.monitor.mapper.SysMachineInfoMapper
import com.itdct.onflow.system.monitor.mapper.SysMachineReportMapper
import org.springframework.stereotype.Component
import oshi.hardware.CentralProcessor
import java.lang.management.ManagementFactory
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.*
import kotlin.math.max

/**
 * @author DCTANT
 * @date 2025-10-16 09:59:44
 * @version 1.0
 * @description 服务器监控数据上报中间层
 */
@Component
class SysMachineReportManager(
    val sysMachineReportMapper: SysMachineReportMapper,
    val monitorConfig: MonitorConfig,
    val sysMachineInfoMapper: SysMachineInfoMapper,
    val redisUtil: RedisUtil,
    val redisReentrantLock: RedisReentrantLock
) : BaseManager() {

    private var prevTicks: LongArray? = null
    private var infoId = 0L
    private var downloadBefore = 0L
    private var uploadBefore = 0L
    private var timestampBefore = 0L
    private var sysMachineInfoEntity: SysMachineInfoEntity? = null
    private var diskReadBefore = 0L
    private var diskWriteBefore = 0L

    fun report(timeKey: String) {
        if (!monitorConfig.enable) {
            logDebug("服务器监控功能未启用")
            return
        }

        val redisKey = timeKey + "-" + monitorConfig.machineId
        val tryLock = redisReentrantLock.tryLock(redisKey, 5, 3)
        if (!tryLock) {
            return
        }

        logDebug("开始上报服务器信息")

        if (infoId == 0L) {
            val ktQueryWrapper = KtQueryWrapper(SysMachineInfoEntity::class.java)
            ktQueryWrapper.eq(SysMachineInfoEntity::machineId, monitorConfig.machineId)
            sysMachineInfoEntity = sysMachineInfoMapper.selectOne(ktQueryWrapper, false)
            if (sysMachineInfoEntity == null) {
                return
            }
            infoId = sysMachineInfoEntity!!.id!!
        }
        val systemInfo = oshi.SystemInfo()
        val hardware = systemInfo.hardware
        val processor = hardware.processor
        val ticks = processor.systemCpuLoadTicks!!
        if (prevTicks == null) {
            prevTicks = ticks
        }

        val sysMachineReportEntity = SysMachineReportEntity()
        sysMachineReportEntity.machineId = monitorConfig.machineId
        sysMachineReportEntity.infoId = infoId

        // INFO: Zhouwx: 2025/10/16 网络相关
        var downloadNow = 0L
        var uploadNow = 0L
        val timestampNow = System.nanoTime()
        val timeDiffInSeconds = (timestampNow - timestampBefore) / 1_000_000_000.0
        for (networkIF in hardware.networkIFs) {
            // 关键修改2：过滤网络接口，只统计物理接口和主要虚拟接口
            if (networkIF.name.startsWith("lo") || networkIF.name.contains("docker") || networkIF.name.contains("veth") || networkIF.name.contains("br-")) {
                continue // 跳过回环、Docker等虚拟接口
            }
            networkIF.updateAttributes()
            downloadNow += networkIF.bytesRecv
            uploadNow += networkIF.bytesSent
        }

        sysMachineReportEntity.networkDownload = BigDecimal(downloadNow - downloadBefore).divide(BigDecimal(timeDiffInSeconds), 0, RoundingMode.HALF_UP).toLong()
        sysMachineReportEntity.networkUpload = BigDecimal((uploadNow - uploadBefore)).divide(BigDecimal(timeDiffInSeconds), 0, RoundingMode.HALF_UP).toLong()

        downloadBefore = downloadNow
        uploadBefore = uploadNow

        // INFO: Zhouwx: 2025/10/16 硬盘使用率相关
        var diskStoreTotal = 0L
        var readTotal = 0L
        var writeTotal = 0L
        for (diskStore in hardware.diskStores) {
            diskStoreTotal += diskStore.size
            diskStore.updateAttributes()
            readTotal += diskStore.readBytes
            writeTotal += diskStore.writeBytes
        }

        var diskTotalFree = 0L
        val fileSystem = systemInfo.operatingSystem.fileSystem
        for (fileStore in fileSystem.fileStores) {
            diskTotalFree += fileStore.freeSpace
        }

        sysMachineReportEntity.storageTotal = diskStoreTotal
        sysMachineReportEntity.storageInUse = diskStoreTotal - diskTotalFree
        sysMachineReportEntity.storageUsage = BigDecimal(sysMachineReportEntity.storageInUse * 100).divide(BigDecimal(sysMachineReportEntity.storageTotal), 2, RoundingMode.HALF_UP)

        sysMachineReportEntity.diskRead = BigDecimal(readTotal - diskReadBefore).divide(BigDecimal(timeDiffInSeconds), 0, RoundingMode.HALF_UP).toLong()
        sysMachineReportEntity.diskWrite = BigDecimal(writeTotal - diskWriteBefore).divide(BigDecimal(timeDiffInSeconds), 0, RoundingMode.HALF_UP).toLong()

        diskReadBefore = readTotal
        diskWriteBefore = writeTotal

        // INFO: Zhouwx: 2025/10/16 处理CPU相关信息，代码来源于MooInfo项目（https://gitee.com/zhoubochina/MooInfo.git）
        val user: Long = ticks[CentralProcessor.TickType.USER.index] - prevTicks!!.get(CentralProcessor.TickType.USER.index)
        val nice: Long = ticks[CentralProcessor.TickType.NICE.index] - prevTicks!!.get(CentralProcessor.TickType.NICE.index)
        val cSys: Long = ticks[CentralProcessor.TickType.SYSTEM.index] - prevTicks!!.get(CentralProcessor.TickType.SYSTEM.index)
        val ioWait: Long = ticks[CentralProcessor.TickType.IOWAIT.index] - prevTicks!!.get(CentralProcessor.TickType.IOWAIT.index)
        val idle: Long = ticks[CentralProcessor.TickType.IDLE.index] - prevTicks!!.get(CentralProcessor.TickType.IDLE.index)
        val irq: Long = ticks[CentralProcessor.TickType.IRQ.index] - prevTicks!!.get(CentralProcessor.TickType.IRQ.index)
        val softIrq: Long = ticks[CentralProcessor.TickType.SOFTIRQ.index] - prevTicks!!.get(CentralProcessor.TickType.SOFTIRQ.index)
        val steal: Long = ticks[CentralProcessor.TickType.STEAL.index] - prevTicks!!.get(CentralProcessor.TickType.STEAL.index)
        val totalCpu = max((user + nice + cSys + idle + ioWait + irq + softIrq + steal).toDouble(), 0.0).toLong()
        var free: BigDecimal
        if (totalCpu == 0L) {
            return
        } else {
            free = BigDecimal(idle * 100).divide(BigDecimal(totalCpu), 2, RoundingMode.HALF_UP)
        }
        prevTicks = ticks

        val cpuUsage = BigDecimal(100).subtract(free)
        sysMachineReportEntity.cpuUsage = cpuUsage

        val currentFreq = processor.currentFreq
        val totalFreq = BigDecimal(0)
        for (l in currentFreq) {
            totalFreq.add(BigDecimal(l))
        }
        sysMachineReportEntity.cpuFreq = totalFreq.divide(BigDecimal(currentFreq.size), 2, RoundingMode.HALF_UP).divide(BigDecimal(1000000000), 2, RoundingMode.HALF_UP)

        // INFO: Zhouwx: 2025/10/16 处理内存相关信息
        val memory = hardware.memory
        val total = memory.total
        val usedMemory = total - memory.available
        sysMachineReportEntity.physicalMemoryTotal = total
        sysMachineReportEntity.physicalMemoryInUse = usedMemory
        val virtualMemory = memory.virtualMemory
        val swapTotal = virtualMemory.swapTotal
        val swapUsed = virtualMemory.swapUsed
        sysMachineReportEntity.virtualMemoryTotal = swapTotal
        sysMachineReportEntity.virtualMemoryInUse = swapUsed
        val totalSysMemory = total + swapTotal
        val totalSysUsedMemory = usedMemory + swapUsed
        sysMachineReportEntity.memoryUsage = BigDecimal(totalSysUsedMemory * 100).divide(BigDecimal(totalSysMemory), 2, RoundingMode.HALF_UP)

        // 获取MemoryMXBean
        val memoryMXBean = ManagementFactory.getMemoryMXBean()
        // 获取堆内存使用情况（存储对象实例）
        val heapUsage = memoryMXBean.heapMemoryUsage
        // 获取非堆内存使用情况（如方法区、JVM内部结构）
        val nonHeapUsage = memoryMXBean.nonHeapMemoryUsage
        val totalJvmMemory = heapUsage.max + nonHeapUsage.max
        val usedJvmMemory = heapUsage.used + nonHeapUsage.used
        sysMachineReportEntity.jvmMemoryTotal = totalJvmMemory
        sysMachineReportEntity.jvmMemoryInUse = usedJvmMemory
        sysMachineReportEntity.jvmMemoryUsage = BigDecimal(usedJvmMemory * 100).divide(BigDecimal(totalJvmMemory), 2, RoundingMode.HALF_UP)

        sysMachineReportMapper.insertEx(sysMachineReportEntity)

        sysMachineInfoEntity?.also {
            it.onlineState = SysMachineInfoConst.ONLINE
            it.lastReportDate = Date()
            sysMachineInfoMapper.updateEx(it)
        }

        timestampBefore = timestampNow
        redisReentrantLock.unlock(timeKey)
        logDebug("完成上报服务器信息")
    }

    fun cleanData() {
        val calendar = Calendar.getInstance()
        calendar.add(Calendar.DATE, -monitorConfig.expireTime)
        sysMachineReportMapper.deleteExpireData(calendar.time)
    }
}